#include <stdlib.h>
#include "Tag.h"
#ifndef OK
  #define OK 0
#endif

/*
PRE: Recibe un TAG y un subtag a buscar.
POS:Si el subtag buscado pertenece a la lista de subtags del TAG enviado devuelve OK sino -1.
*/
int buscar_subtags(tipoTag* etiqueta, char* clave){
  int i;
  for (i=0;i<etiqueta->cant_subtags;i++){
    if (!strcmp(etiqueta->subtags[ i ],clave))
      return OK;
  }
return -1;
}

/*
PRE: Recive un vector de tags, su cantodad de elementos, un TAG a buscar y una variable para devolver la posicion del TAG a buscar.
POS: Devuelve la pocicion del TAG buscado. Si lo encuntra devulve OK y sino -1.
*/
int buscar_tags(tipoTag vec_tags[], int cant_tags, char* clave, int* tag_buscado){
  int i;
  for (i=0;i<cant_tags;i++){
    if (!strcmp(vec_tags[i].tag,clave)){
      *tag_buscado=i;
      return OK;
    }
  }
  return -1;
}

/*
PRE: Recibe un TAG y un nombre de TAG.
POS: Graba el nombre del TAG en el TAG recibido.
*/
int set_tag(tipoTag* tags, char* tag){
  tags->tag=strdup(tag);
  return 0;
}

/*
PRE: Recibe un TAG, una lista de subtags y la cantidad de subtags.
POS: Guarda la lista y la cantidad de subtags adentro del TAG.
*/
int set_subtags(tipoTag* tag, char** subtags,int cant_subtags){
  int i;
  tag->subtags=(char**)malloc(sizeof(char*)*cant_subtags);
  for (i=0;i<cant_subtags;i++){
    tag->subtags[i]=(char*)malloc(sizeof(char)*(strlen(subtags[i])+1));
    tag->subtags[i]=strdup(subtags[i]);
  }
  tag->cant_subtags=cant_subtags;
  return OK;
}

/*
PRE: Recibe una lista de subtags y la cantidad de elementos de la lista
POS: Libera la memoria de esa lista.
*/
int limpiar_subtags(char** subtags,int cant_subtags){
 int i;
  for (i=0;i< cant_subtags;i++)
    if (subtags[i]!=NULL){
        free(subtags[i]);
    }
  free(subtags);
  return 0;
}

/*
linea sin blacos es el vector con todos los tokens no iguales a " "
cont_tok es la cantidad de posiciones del vector

si no encuentra ningun token distinto de espacio entonces te devuelve a cont_tok igual a 0
para que se sepa que ese renglon esta vacio
*/
void sacar_blancos (char* linea , char***  linea_sin_blancos, int* cont_tok){
  int i=0;
  int exeStatus;
  int a;
  Parser parser;
  Parametros lista_parametros;
  *cont_tok=0;
  lista_parametros.vec_parametros=NULL;
  lista_parametros.cant=0;
  exeStatus =agregar_parametro(&lista_parametros,"{");
  exeStatus =agregar_parametro(&lista_parametros,"}");
  exeStatus =agregar_parametro(&lista_parametros," ");
  exeStatus = parser_New ( &parser, &lista_parametros);
  exeStatus = Parsear (&parser, linea);

  (*linea_sin_blancos)=(char**)malloc(sizeof(char*)*1);
  while (i < parser.tokensMax){
    if ((a=strcmp(parser.tokens [ i ]," "))!=0 && (a=strcmp(parser.tokens [ i ],"\n")!=0)&& (a=strcmp(parser.tokens [ i ],"\\")!=0)){
      (*cont_tok)++;
      if ((*linea_sin_blancos)!=NULL ){
      (*linea_sin_blancos)=(char**) realloc(*linea_sin_blancos ,sizeof(char**) * (*cont_tok));
      (*linea_sin_blancos)[(*cont_tok)-1]= (char*) malloc (sizeof(char) * (strlen (parser.tokens[ i ]) +1) );
      strcpy( (*linea_sin_blancos)[(*cont_tok)-1], parser.tokens[ i ]  );
      }
    }
    i++;
  }
  exeStatus=parser_Destruir(&parser);
}

/*
PRE: Recibe la lista de los tokens resultantes de suprimir los espacios en blancos con su respectiva cantidad.
POS: Libera la memoria reservada de la lista de linea_sin_blancos.
*/
void destruir_linea(int cont_tok, char*** linea_sin_blancos  ){
  int i;
  for (i=0; i<cont_tok; i++ ){
    free(  (*linea_sin_blancos)[ i ]);
  }
  free ( (*linea_sin_blancos) );
}

/*
PRE: Recibe la direccin de memoria de una variable tipoTag para devolver el dato allado, recibe una lista
     de los tokens de la linea leida sin los espacios con su cantidad de elementos  y recibe el buffer termporal
     y la posicion actual par poder analizarlo.
POS: Valida los tokens de una linea en busca de un TAG valido para cargar. Si no es valido devuelve -1. Si es valido
     lo graba en la variable TAG y puede devolver el index modificado dependiendo de la cantidad de lecturas que aya echo.
*/
int buscar_tag_a_cargar(tipoTag* tag,char** linea_sin_blancos,int cont_tok,char** buffer, int* index){

  char** linea_sin_blancos2;
  int index2;
  if (cont_tok>2) return -1;
  if (cont_tok<=0) return -1;
  if (cont_tok==2){ /*Si la linea leida tiene 2 token*/
    if (strstr(linea_sin_blancos[1],"{")==NULL){
      fprintf(stderr,"Error: Se esperaba '{' para validar el TAG\n");
      return -1; /* si el segundo token no es '{' entonces el contenido de la linea no es valido*/
      }
    tag->tag=strdup(linea_sin_blancos[0]); /* Si el segundo token es '{' entonces guarda al primero como la etiqueta del TAG a cargar*/
    return 0;
  }
  if (cont_tok==1){ /*Si la linea solo tiene un token*/
    index2=(*index)+1;
    sacar_blancos ( buffer[index2], & linea_sin_blancos2, &cont_tok);/*hace una nueva lectura para ver y analizar el proximo token*/
    if(strstr(linea_sin_blancos2[0],"{")!=NULL){/*Si el proximo token es '{'*/
      tag->tag=strdup(linea_sin_blancos[0]); /*Graba la etiqueta en la variable*/
      destruir_linea(cont_tok, & linea_sin_blancos2  );
      *index=index2;
      return 0;
    }else{
      destruir_linea(cont_tok, & linea_sin_blancos2  );
      fprintf(stderr,"Error: La linea leida no era un TAG.\n");
      return -1; /*Devuelve -1 para inforar que no es un TAG valido y debe ser ignorado*/
    }
  }
  return 0;
}

/*
PRE: Recibe un vector de TAGs con su cantidad y la ruta de un archivo realizar la carga.
POS: Devuelve el vector de TAGs cargado y su cantidad de elementos.
*/
int Cargar_tag_ArchConf (tipoTag vec_tags[],int* cant_vec_tags,char* ruta_arch_conf){

/*Declaracion de variables>>>>>>>>>>>>>>>>>>>>>>>>*/
  FILE* archivo;
  int errorCode,error,cont_tok,i,index,cont=0;
  char* linea = NULL;
  char* temp = NULL;
  char** linea_sin_blancos=NULL;
  char** buffer=(char**)malloc(sizeof(char*));
  tipoTag tag;
  tag.subtags=(char**)malloc(sizeof(char*));
  tag.cant_subtags=0;
/*Declaracion de variables<<<<<<<<<<<<<<<<<<<<<<<<*/

/*Carga el buffer>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
  archivo = fopen(ruta_arch_conf,"rt");
  while (!feof(archivo)){
    errorCode = getString(&linea, archivo);
    if(errorCode == OK){
      cont++;
      buffer=(char**)realloc(buffer,sizeof(char*)*cont);
      buffer[cont-1]=(char*)malloc(sizeof(char)*(strlen(linea)+1));
      strcpy(buffer[cont-1],linea);
    }else{
      fclose(archivo);
      fprintf(stderr,"Error de lectura en el archivo de configuracion.\n");
      return errorCode;
    }
    free(linea);
  }
/*Carga el buffer<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/

  index=0;
  while (index<cont){
    sacar_blancos ( buffer[index], & linea_sin_blancos, &cont_tok);
    if (buscar_tag_a_cargar(&tag,linea_sin_blancos,cont_tok,buffer,&index)==0){
      temp=(char*)malloc(sizeof(char)*(strlen(linea_sin_blancos[0])+1));
      for(i=0;i<strlen(linea_sin_blancos[0])+1;i++){
        temp[i]=linea_sin_blancos[0][i];
      }
      strcpy(tag.tag,temp);
      set_tag( &(vec_tags[*cant_vec_tags]), linea_sin_blancos[0]);
      destruir_linea(cont_tok, & linea_sin_blancos  );
      error=0;
      sacar_blancos ( buffer[index], & linea_sin_blancos, &cont_tok);
      while ((linea_sin_blancos[0]!="")&&(!strstr(linea_sin_blancos[0],"}"))&&index<cont){
        destruir_linea(cont_tok, & linea_sin_blancos  );
        index++;
        sacar_blancos ( buffer[index], & linea_sin_blancos, &cont_tok);
        if (cont_tok>0){
          if ((linea_sin_blancos[0]!="")&&(!strstr(linea_sin_blancos[0],"}"))){
            (tag.cant_subtags)++;
            tag.subtags=(char**)realloc(tag.subtags,sizeof(char*)*(tag.cant_subtags));
            tag.subtags[tag.cant_subtags-1]=(char*)malloc(sizeof(char)*(strlen(linea_sin_blancos[0])+1));
            tag.subtags[tag.cant_subtags-1]=strdup(linea_sin_blancos[0]);
          }
          if ((linea_sin_blancos[0]!="")) error=1;
        }
      }
      (*cant_vec_tags)++;
      set_subtags(&(vec_tags[*cant_vec_tags-1]),tag.subtags,tag.cant_subtags);
      limpiar_subtags(tag.subtags,tag.cant_subtags);
      tag.subtags=(char**)malloc(sizeof(char*));
      tag.cant_subtags=0;
      destruir_linea(cont_tok, & linea_sin_blancos  );
    }else{
      destruir_linea(cont_tok, & linea_sin_blancos  );
    }
      index++;
  }
  fclose(archivo);
  free(linea);
  return 0;
}
